#include "main.h"
#include "stm32f4xx_hal.h"
#include "adc.h"
#include "dma.h"
#include "i2c.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

#include "stdio.h"
#include "zlg7290.h"
#include "Dc_motor.h"

#define ZLG_READ_ADDRESS1         0x01
#define ZLG_READ_ADDRESS2         0x10
#define ZLG_WRITE_ADDRESS1        0x10
#define ZLG_WRITE_ADDRESS2        0x11
#define PASS ;
#define Stable 1
#define ReadyToTurn 2



__IO uint16_t adcx[3]={0};
float lightValue_original, fireValue_original, airValue_original;
float lightValue,fireValue,airValue;
int angle = 1000;
int Debug_ON = 1;
int Auto_ON = 1;
uint8_t keyPressed = 0;


void SystemClock_Config(void);
void LCD_Clear(void);
void ReadSensor();
unsigned char TransformKeyToI2CData(int key);
void ShowSensorData2LCD();
void SteeringEngineControler();
void ScanSerialPort();
void TryAlarming();
void ScanNumpad();

int main(void)
{
	HAL_Init();
	SystemClock_Config();
	MX_GPIO_Init();
	MX_DMA_Init();
	MX_ADC3_Init();
	MX_I2C1_Init();
	MX_USART1_UART_Init();
	MX_TIM12_Init();
	MX_TIM3_Init();

	HAL_ADC_Start_DMA(&hadc3,(uint32_t*)adcx,3);
	HAL_TIM_PWM_Start(&htim12, TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim12, TIM_CHANNEL_1);
	DC_Motor_Pin_Low();
	HAL_TIM_Base_Start_IT(&htim3);
  	while (1)
  	{
  		ReadSensor();
		ShowSensorData2LCD();
		TryAlarming();
		ScanNumpad();
		ScanSerialPort();
		SteeringEngineControler();
	}
}

void SystemClock_Config(void)
{

  RCC_OscInitTypeDef RCC_OscInitStruct;
  RCC_ClkInitTypeDef RCC_ClkInitStruct;

    /**Configure the main internal regulator output voltage 
    */
  __HAL_RCC_PWR_CLK_ENABLE();

  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 25;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = 4;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Initializes the CPU, AHB and APB busses clocks 
    */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure the Systick interrupt time 
    */
  HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

    /**Configure the Systick 
    */
  HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

  /* SysTick_IRQn interrupt configuration */
  HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);
}

/* USER CODE BEGIN 4 */

void ReadSensor(){
	lightValue_original = adcx[0];
	fireValue_original = adcx[1];
	airValue_original = adcx[2];
	lightValue = (float)lightValue_original*(100.0/4096);
	lightValue = -(lightValue - 100);
	fireValue = (float)fireValue_original*(100.0/4096);
	airValue = (float)airValue_original*(100.0/2048);
}
void LED_ON(int lednum){
		switch(lednum){
			case 1:
				HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_RESET); /*D1*/
				break;
			case 2:
				HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_RESET);  /*D2*/
				break;
			case 3:
				HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET); /*D3*/
				break;
			case 4:
				HAL_GPIO_WritePin(GPIOH,GPIO_PIN_15,GPIO_PIN_RESET); /*D4*/
				break;
			default:
				break;
		}
}
void LED_OFF(int lednum){
		switch(lednum){
			case 1:
				HAL_GPIO_WritePin(GPIOC,GPIO_PIN_0,GPIO_PIN_SET);   /*D1*/
				break;
			case 2:
				HAL_GPIO_WritePin(GPIOH,GPIO_PIN_15,GPIO_PIN_SET);  /*D2*/
				break;
			case 3:
				HAL_GPIO_WritePin(GPIOF,GPIO_PIN_10,GPIO_PIN_SET);  /*D3*/
				break;
			case 4:
				HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);  /*D4*/
				break;
			default:
				break;
		}
}
void LED_ON_ALL(){
	LED_ON(1);
	LED_ON(2);
	LED_ON(3);
	LED_ON(4);
}
void LED_OFF_ALL(){
	LED_OFF(1);
	LED_OFF(2);
	LED_OFF(3);
	LED_OFF(4);
}
void LED_Twinkle(){
  	LED_ON_ALL();
  	HAL_Delay(50);
	LED_OFF_ALL();
  	HAL_Delay(50);
}
void LED_Loop(){
	static int direction = 1;
	static int lednum = 1;
	int delay = 150;
	if(direction == 1){
		LED_OFF_ALL();
		LED_ON(lednum);
		lednum++;
		if(lednum > 4){
			lednum = 4;
			direction = 2;
		}
	}else{
		LED_OFF_ALL();
		LED_ON(lednum);
		lednum--;
		if(lednum < 1){
			lednum = 1;
			direction = 1;
		}
	}
}
void Beeper_On(){
	HAL_GPIO_WritePin(GPIOG,GPIO_PIN_6,GPIO_PIN_SET);//Turn on Beeper
}
void Beeper_Off(){
	HAL_GPIO_WritePin(GPIOG,GPIO_PIN_6,GPIO_PIN_RESET);//Turn off Beeper
}
void Beeper_Beep(){
	for(int i = 0; i < 50; i++){
		Beeper_On();
		HAL_Delay(1);
		Beeper_Off();
		HAL_Delay(1);
	}
}
void DCMotor_ON(){
	DC_Task(0x1C);
}
void DCMotor_OFF(){
	DC_Task(0);
}
void NoAlarming(){
	LED_Loop();
	DCMotor_OFF();
}
void Alarming(){
	LED_Twinkle();
	Beeper_Beep();
}
void Alarming_low(){
	static int lock = 1;
	if(lock){
		lock = 0;
		return;
	}else{
		lock = 1;
		Alarming();
		DCMotor_ON();
	}
}
void TryAlarming(){
	if((int)fireValue >= 20){
		Alarming();
 	}
	else if((int)airValue >= 40){
		Alarming_low();
	}
	else
		NoAlarming();
}
unsigned char TransformKeyToI2CData(int key){
	switch(key){
			case 0:
				return 0xFC;
			case 1:
				return 0x0c;
			case 2:
				return 0xDA;
			case 3:
				return 0xF2;
			case 4:
				return 0x66;
			case 5:
				return 0xB6;
			case 6:
				return 0xBE;
			case 7:
				return 0xE0;
			case 8:
				return 0xFE;
			case 9:
				return 0xE6;
			default:
				break;
	}
	return 0;
}
int TransformI2CDataToKey(unsigned char data)
{
	switch(data)
	{
        case 0x1C:
			return 1;					
        case 0x1B:	
			return 2;
        case 0x1A:	
			return 3;
        case 0x14:
			return 4;
		case 0x13:
			return 5;
        case 0x12:
			return 6;
        case 0x0C:
			return 7;
        case 0x0B:
         	return 8;
		case 0x0A:
			return 9;
        default:
          break;
	}
	return -1;
}
void ShowSensorData2LCD(){
	if(lightValue > 99)	lightValue = 99;
	if(fireValue > 99)	fireValue = 99;
	if(airValue > 99)	airValue = 99;

	unsigned char tenOfLight = (int)lightValue/10;
	unsigned char oneOfLight = (int)lightValue%10;

	unsigned char tenOfFire = (int)fireValue/10;
	unsigned char oneOfFire = (int)fireValue%10;

	unsigned char tenOfAir = (int)airValue/10;
	unsigned char oneOfAir = (int)airValue%10;

	tenOfLight = TransformKeyToI2CData(tenOfLight);
	oneOfLight = TransformKeyToI2CData(oneOfLight);
	tenOfFire = TransformKeyToI2CData(tenOfFire);
	oneOfFire = TransformKeyToI2CData(oneOfFire);
	tenOfAir = TransformKeyToI2CData(tenOfAir);
	oneOfAir = TransformKeyToI2CData(oneOfAir);

	unsigned char writeBuffer[8] = {tenOfLight, oneOfLight, 0, tenOfFire, oneOfFire, 0, tenOfAir, oneOfAir};
	I2C_ZLG7290_Write(&hi2c1,0x70,ZLG_WRITE_ADDRESS1,writeBuffer,8);
}
void InputProcessing(int input){
	switch(input){
		case 1:
			angle += 100;
			Auto_ON = 0;
			break;
		case 2:
			angle -= 100;
			Auto_ON = 0;
			break;
		case 3:
			if(Auto_ON)
				Auto_ON = 0;
			else
				Auto_ON = 1;
	}
}
int GetInputKey(){
	unsigned char I2CDataBuffer[1];
	I2C_ZLG7290_Read(&hi2c1,0x71,0x01,I2CDataBuffer,1);
	int key = TransformI2CDataToKey(I2CDataBuffer[0]);
	return key;
}
void ScanNumpad(){
	if(keyPressed){
		keyPressed = 0;
		InputProcessing(GetInputKey());
	}
}

int Myabs(int num){
	if(num <  0)
		return -num;
	else return num;
}

void SteeringEngine_SetAngleByLight(){
	static __int16 presetAngle = 1000, lastPresetAngle = 1000;
	static __int8 engineStatus = Stable;

	presetAngle = (int)(lightValue_original / 1.6);
	if(engineStatus == Stable){
		if(Myabs(presetAngle - lastPresetAngle) > 50)
			engineStatus = ReadyToTurn;
	}else if(engineStatus == ReadyToTurn)
		if(Myabs(presetAngle - lastPresetAngle) < 50){
			angle = presetAngle;
			engineStatus = Stable;
		}
	lastPresetAngle = presetAngle;
}
void SteeringEngine_CheckAngle(){
	if(angle > 2500)
		angle = 2500;
	if(angle < 500)
		angle = 500;
}
void SteeringEngine_Turn(){
	static int engineAngle = 1000;
	while(engineAngle != angle){
		if(engineAngle < angle)	engineAngle += 1;
		else if(engineAngle > angle)	engineAngle -= 1;
		__HAL_TIM_SET_COMPARE(&htim12,TIM_CHANNEL_1,engineAngle);
		HAL_Delay(1);
	}
}
void SteeringEngineControler(){
	if(Auto_ON)
		SteeringEngine_SetAngleByLight();
	SteeringEngine_CheckAngle();
	SteeringEngine_Turn();
}

void ScanSerialPort(){
	unsigned char ReadBuffer[5];
	HAL_UART_Receive(&huart1,ReadBuffer,1,100);
	if(Debug_ON)
		printf("\r\n ReadBuffer=%d\n\r",ReadBuffer[0]);
	if(ReadBuffer[0] != 0){
		if(ReadBuffer[0] == '1')
		{
			InputProcessing(1);
		}
		else if(ReadBuffer[0] == '2')
		{
			InputProcessing(2);
		}
		else if(ReadBuffer[0] == '3')
		{
			InputProcessing(3);
		}
		ReadBuffer[0]=0;
	}
	
}


int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR&0X40)==0);//???????,??????????   
	USART1->DR = (uint8_t) ch;      
	return ch;
}

void LCD_Clear(void)
{
	uint8_t Tx1_Buffer[8]={0};
	I2C_ZLG7290_Write(&hi2c1,0x70,ZLG_WRITE_ADDRESS1,Tx1_Buffer,8);
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	keyPressed = 1;
}



/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  file: The file name as string.
  * @param  line: The line in file as a number.
  * @retval None
  */
void _Error_Handler(char *file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
